package cn.imokay;

import cn.imokay.entity.Author;
import cn.imokay.entity.Book;
import org.junit.Before;
import org.junit.Test;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class SteamDemo {

    List<Author> authors;

    @Before
    public void getAuthors() {
        System.out.println("初始化数据");
        authors = Author.getAuthors();
    }

    @Test
    public void demo1() {
        /*打印年龄小于18的作家*/
        authors.stream()
                .distinct()
                .filter(author -> author.getAge() < 18)
                .forEach(author -> System.out.println(author.getName()));
    }

    @Test
    public void mapTest() {
        //通过map转换，将流中的对象转换成字符串
        authors.stream()
                .filter(author -> author.getAge() < 18)
                .map(author -> author.getName())
                .forEach(s -> System.out.println(s));
    }

    @Test
    public void mapTest2() {
        //map，年龄加10岁
        authors.stream()
                .map(author -> author.getAge())
                .map(age -> age + 10)
                .forEach(age -> System.out.println(age));
    }

    @Test
    public void filterTest() {
        /*打印年龄小于18的作家*/
        authors.stream()
                .distinct()
                .filter(author -> author.getAge() < 18)
                .forEach(author -> System.out.println(author.getName()));
    }

    @Test
    public void sortedTest2() {
        //按年龄排序，使用有参
        authors.stream()
                .sorted((o1, o2) -> o1.getAge() - o2.getAge())
                .forEach(author -> System.out.println(author.getAge()));
    }

    @Test
    public void sortedTest() {
        //按年龄排序,使用空参的sort方法时，需要对象实现compareble接口
        authors.stream()
                .sorted()
                .forEach(author -> System.out.println(author.getAge()));
    }

    @Test
    public void limitTest() {
        //打印年龄最大的两个作家的姓名
        authors.stream()
                .sorted(new Comparator<Author>() {
                    @Override
                    public int compare(Author o1, Author o2) {
                        return o2.getAge() - o1.getAge();
                    }
                })
                .limit(2)
                .forEach(author -> System.out.println(author.getName() + " " + author.getAge()));
    }

    @Test
    public void skipTest() {
        //d打印排除年龄最大的作家姓名，降序排列
        authors.stream()
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .skip(1)
                .forEach(author -> System.out.println(author.getName() + " " + author.getAge()));
    }

    @Test
    public void flatMapTest() {
        //打印所有作家的书籍作品
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .forEach(book -> System.out.println(book));
    }

    @Test
    public void flatMapTest2() {
        //打印所有作家的书记中非战争类型的数据
        authors.stream()
                .flatMap(a -> a.getBooks().stream())
                .distinct()
                .filter(book -> !book.getCatagory().contains("战争"))
                .forEach(book -> System.out.println(book));
    }

    @Test
    public void flatTest3() {
        //打印所有书籍分类，去重，去掉战争类
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .flatMap(book -> Arrays.stream(book.getCatagory().split(",")))
                .distinct()
                .filter(s -> !s.contains("战争"))
                .forEach(s -> System.out.println(s));

    }

    /*
     * 终止操作，foreach，count，max，min
     * */
    @Test
    public void countTest() {
        //统计所以有作家的所有作品总数
        long count = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .count();

        System.out.println(count);
    }

    @Test
    public void maxTest() {
        //min的用法与max用法一致
        Optional<Integer> max = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .max((o1, o2) -> o1 - o2);
        System.out.println(max.get());
    }

    @Test
    public void minTest() {
        //min的用法与max用法一致
        Optional<Book> min = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .min((o1, o2) -> o1.getScore() - o2.getScore());
        System.out.println(min.get().getScore());
    }

    @Test
    public void collectTest() {
        //获取存放所有作者名字的集合
        List<String> collect = authors.stream()
                .map(a -> a.getName())
                .collect(Collectors.toList());

        System.out.println(collect);

    }

    @Test
    public void collectTest2() {
        //获取存放所有作者名字的集合
        Set<String> collect = authors.stream()
                .map(a -> a.getName())
                .collect(Collectors.toSet());
        System.out.println(collect);
    }

    @Test
    public void collectTest3() {
        //获取map,key为作者名，value为作品list
        Map<String, List<Book>> collect = authors.stream()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));

        System.out.println(collect);
    }

    @Test
    public void anyMatch() {
        //判断年龄是否有28岁以上的作家
        boolean b = authors.stream()
                .anyMatch(author -> author.getAge() > 28);
        System.out.println(b);
    }

    @Test
    public void allMatchTest() {
        //是否所有的作家都时成年人
        boolean b = authors.stream()
                .allMatch(author -> author.getAge() >= 18);
        System.out.println(b);
    }

    @Test
    public void noneMatchTest() {
        //是否所有的作家都不到14岁
        boolean b = authors.stream()
                .noneMatch(author -> author.getAge() < 14);
        System.out.println(b);
    }

    @Test
    public void findAnyTest() {
        //输出任意一个年龄大于18岁的作家名称
        Optional<Author> any = authors.stream()
                .filter(author -> author.getAge() > 10)
                .findAny();
        any.ifPresent(author -> System.out.println(author.getName()));

    }

    @Test
    public void findFirtTest() {
        //输入第一个年龄大于18岁的作家名称
        Optional<Author> any = authors.stream()
                .filter(author -> author.getAge() > 18)
                .findFirst();
        any.ifPresent(author -> System.out.println(author.getName()));
    }

    @Test
    public void findFirtTest2() {
        //输出年龄最大的作家
        Optional<Author> any = authors.stream()
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .findFirst();
        any.ifPresent(author -> System.out.println(author.getName() + author.getAge()));
    }

    @Test
    public void reduceTest() {
        //归并操作  缩  减操作

        //对所与作家年龄求和
        Integer reduce = authors.stream()
                .map(author -> author.getAge())
                .reduce(0, (integer, integer2) -> integer + integer2);
        System.out.println(reduce);
    }

    @Test
    public void reduceTest2() {
        //使用归并获取最大年龄
        Integer reduce = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MIN_VALUE, (integer, integer2) -> integer > integer2 ? integer : integer2);
        System.out.println(reduce);
    }

    @Test
    public void reduceTest3() {
        //使用归并获取最小年龄
        Integer reduce = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, (result, element) -> result < element ? result : element);
        System.out.println(reduce);
    }

    @Test
    public void reduceTest4() {
        //使用归并获取最小年龄
        Integer reduce = authors.stream()
                .map(author -> author.getAge())
                .reduce(0, new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer integer, Integer integer2) {
                        return integer < integer2?integer:integer2;
                    }
                });
        System.out.println(reduce);
    }

    @Test
    public void reduceOptionalTest() {
        //reduce单个参数  获取最小年龄
        Optional<Integer> reduce = authors.stream()
                .map(Author::getAge)
                .reduce((integer, integer2) -> integer < integer2 ? integer : integer2);

        reduce.ifPresent(age -> System.out.println(age));

    }

    @Test
    public void filterAndTest() {
        //年龄大于17，作品2部及以上
        authors.stream()
                .filter(((Predicate<Author>) author -> author.getAge() > 17)
                        .and(author -> author.getBooks().size() > 1))
                .forEach(a -> System.out.println(a.getName()));

    }
}
